#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
/*
    此文件操作是系统级的文件操作，不是C库中的文件操作
    系统级的文件操作，是直接操作文件描述符的，而C库中的文件操作，是通过文件指针来操作的
    c还是c++文件操作底层借助这个底层的文件操作函数来实现的(linux下的底层文件操作函数)
    所以这个没有缓冲直接操作文件描述符与系统内核交互
    在一个进程中，能够打开的文件描述符是有限制的，一般是1024个，[0,1023]，可以通过指令 ulimit -a进行查看，如果要更改这个限制，可以通过指令 ulimit -n 数字，进行更改
    文件描述符的使用原则一般是最小未分配原则
    0、1、2，这三个文件描述符在一个进程启动时就默认被打开了，分别表示标准输入、标准输出、标准错误
    printf("stdin->_fileno = %d\n", stdin->_fileno);    // 0
    printf("stdout->_fileno = %d\n", stdout->_fileno);   //1
    printf("stderr->_fileno = %d\n", stderr->_fileno);   //2



    #include <sys/types.h>  // 保证不同架构和系统的兼容性
    #include <sys/stat.h>   // 提供了文件的属性的结构体和宏
    #include <fcntl.h>      // 定义文件打开/创建的标志和函数原型，是 open() 系统调用的核心依赖。
    int open(const char *pathname, int flags);
    int open(const char *pathname, int flags, mode_t mode);
    功能：打开或创建一个文件，并返回该文件的文件描述符，返回文件描述符的规则是最小未分配原则
    参数1：要打开的文件文件路径
    参数2：打开模式
        以下三种方式必须选其一：O_RDONLY(只读)、O_WRONLY（只写）、O_RDWR（读写）
        以下的打开方式可以有零个或多个，跟上述的方式一起用位或运算连接到一起
        O_CREAT:用于创建文件，如果文件不存在，则创建文件，如果文件存在，则打开文件，如果flag中包含了该模式，则函数的第三个参数必须要加上
        O_APPEND:以追加的形式打开文件，光标定位在结尾
        O_TRUNC:清空文件
        O_EXCL:常跟O_CREAT一起使用，确保本次要创建一个新文件，如果文件已经存在，则open函数报错
        eg:
            "w": O_WRONLY|O_CREAT|O_TRUNC
            "w+": O_RDWR|O_CREAT|O_TRUNC
            "r": O_RDONLY
            "r+": O_RDWR
            "a": O_WRONLY|O_CREAT|O_APPEND
            "a+": O_RDWR|O_CREAT|O_APPEND
    参数3：如果参数2中的flag中有O_CREAT时，表示创建新文件，参数3就必须给定，表示新创建的文件的权限
            如果当前参数给定了创建的文件权限，最终的结果也不一定是参数3的值，系统会用你给定的参数3的值，与系统的umask取反的值进行位与运算后，才是最终创建文件的权限（mode & ~umask）
            当前终端的umask的值，可以通过指令 umask 来查看，一般默认为为 0022，表示当前进程所在的组中对该文件没有写权限，其他用户对该文件也没有写权限
            当前终端的umask的值是可以更改的，通过指令：umask 数字进行更改，这种方式只对当前终端有效
            普通文件的权限一般为：0644，表示当前用户没有可执行权限，当前组中其他用户和其他组中的用户都只有读权限
            目录文件的权限一般为：0755，表示当前用户具有可读、可写、可执行，当前组中其他用户和其他组中的用户都没有可写权限
            注意：如果不给权限，那么当前创建的权限会是一个随机值
    返回值：成功返回打开文件的文件描述符，失败返回-1并置位错误码


    #include <unistd.h>   //提供系统级函数，sleep _exit等
    int close(int fd);
    功能：关闭文件描述符对应的文件
    参数：文件描述符
    返回值：成功返回0，失败返回-1并置位错误码
*/
int main(int argc, const char *argv[])
{
    // 1、定义文件描述符，对于文件IO而言，句柄就是文件描述符
    int fd = -1;
    // 以只读的形式创建文件，如果文件不存在则创建文件
    // 如果创建文件时没有给权限，则该文件的权限是随机权限
    // 如果创建文件时，给定了文件的权限，则文件最终的权限是 给定的 mode&~umask
    if ((fd = open("./tt.txt", O_WRONLY | O_CREAT, 0644)) == -1)
    {
        perror("open error");
        return -1;
    }
    printf("open success fd = %d\n", fd); // 3,由于0、1、2已经被使用，所以该数为3
    // 关闭文件
    close(fd); // 关闭fd引用的文件
    return 0;
}
